#include <inttypes.h>
#include <avr/io.h>

#include "uart.h"
#include "common.h"
#include "protocol.h"

void uart_parser(char *buf)
{
  answer[0] = buf[0];

  switch(buf[0])
  {
    case CMD_UART_INIT:
      uart_init_usb((char)buf[2]);
      break;
    case CMD_UART_DEINIT:
      uart_deinit_usb((char)buf[2]);
      break;

    case CMD_UART_BAUDRATE:
                      // uartport       UBRRnL        UBRRnH
      uart_baudrate_usb((char)buf[2], (char)buf[3], (char)buf[4]);
      break;
    case CMD_UART_STOPBITS:
      uart_stopbits_usb((char)buf[2], (char)buf[3]);
      break;
    case CMD_UART_DATABITS:
      uart_stopbits_usb((char)buf[2], (char)buf[3]);
      break;
    case CMD_UART_PARITY:
      uart_parity_usb((char)buf[2], (char)buf[3]);
      break;

    case CMD_UART_SEND:
      uart_send_usb((char)buf[2], (char)buf[3], &buf[4]);
      break;
    case CMD_UART_RECV:
      uart_recv_usb((char)buf[2], (char)buf[3]);
      break;
    default:
      answer[1] = RSP_UNKOWN_CMD;
      answer[2] = 0;
      CommandAnswer(3);
  }
}

void uart_init_usb(char uartport)
{
   answer[1] = (unsigned char)uart_init(uartport);
   answer[2] = 0;

   CommandAnswer(3);
}

char uart_init(char uartport)
{
  switch(uartport)
  {
    case 0:
      octopus.ports[41] = PIN_UART;
      octopus.ports[42] = PIN_UART;
      /* enable transmitter receiver */
      UCSR0B = (1 << RXEN0) | (1 << TXEN0);
      break;
    case 1:
      octopus.ports[14] = PIN_UART;
      octopus.ports[15] = PIN_UART;
      /* enable transmitter receiver */
      UCSR1B = (1 << RXEN1) | (1 << TXEN1);
      break;
    default:
      return RSP_UNKOWN_PIN;
  } 

  return RSP_OK; 
}

void uart_deinit_usb(char uartport)
{
   answer[1] = (unsigned char)uart_deinit(uartport);
   answer[2] = 0;

   CommandAnswer(3);
}

char uart_deinit(char uartport)
{
  switch(uartport)
  {
    case 0:
      octopus.ports[41] = PIN_NONE;
      octopus.ports[42] = PIN_NONE;
      UBRR0H = 0;
      UBRR0L = 0;
      UCSR0B = 0;
      UCSR0C = 0;
      break;
    case 1:
      octopus.ports[14] = PIN_NONE;
      octopus.ports[15] = PIN_NONE;
      UBRR1H = 0;
      UBRR1L = 0;
      UCSR1B = 0;
      UCSR1C = 0;
      break;
    default:
      return RSP_UNKOWN_PIN;
  } 

  return RSP_OK; 
}

void uart_baudrate_usb(char uartport, char ubrrl, char ubrrh)
{
   answer[1] = (unsigned char)uart_baudrate(uartport, ubrrl, ubrrh);
   answer[2] = 0;

   CommandAnswer(3);
}

char uart_baudrate(char uartport, char ubrrl, char ubrrh)
{
  switch(uartport)
  {
    case 0:
      UBRR0H = ubrrh;
      UBRR0L = ubrrl;
      break;
    case 1:
      UBRR1H = ubrrh;
      UBRR1L = ubrrl;
      break;
    default:
      return RSP_UNKOWN_PIN;
  }

  return RSP_OK; 
}

void uart_stopbits_usb(char uartport, char stopbits)
{
   answer[1] = (unsigned char)uart_stopbits(uartport, stopbits);
   answer[2] = 0;

   CommandAnswer(3);
}

char uart_stopbits(char uartport, char stopbits)
{
  char usbs;

  switch(stopbits)
  {
    case 1:  usbs = 0; break;
    case 2:  usbs = 2; break;
    default: usbs = 0; break;
  }

  switch(uartport)
  {
    case 0:
      UCSR0C |= (usbs << USBS0);
      break;
    case 1:
      UCSR1C |= (usbs << USBS1);
      break;
    default:
      return RSP_UNKOWN_PIN;
  }

  return RSP_OK; 
}

void uart_databits_usb(char uartport, char databits)
{
   answer[1] = (unsigned char)uart_databits(uartport, databits);
   answer[2] = 0;

   CommandAnswer(3);
}

char uart_databits(char uartport, char databits)
{
  char ucsz1,ucsz0;

  switch(databits) {
    case 5:  ucsz1 = 0; ucsz0 = 0; break;
    case 6:  ucsz1 = 0; ucsz0 = 1; break;
    case 7:  ucsz1 = 1; ucsz0 = 0; break;
    case 8:  ucsz1 = 1; ucsz0 = 1; break;
    default: ucsz1 = 1; ucsz0 = 1; break;
  }

  switch(uartport)
  {
    case 0:
      UCSR0C |= (ucsz1 << UCSZ01) | (ucsz0 << UCSZ00);
      break;
    case 1:
      UCSR1C |= (ucsz1 << UCSZ11) | (ucsz0 << UCSZ10);
      break;
    default:
      return RSP_UNKOWN_PIN;
  }

  return RSP_OK; 
}

void uart_parity_usb(char uartport, char parity)
{
   answer[1] = (unsigned char)uart_databits(uartport, parity);
   answer[2] = 0;

   CommandAnswer(3);
}

char uart_parity(char uartport, char parity)
{
  char upm1, upm0;
  switch(parity)
  {
    case 'N': upm1 = 0; upm0 = 0; break;
    case 'E': upm1 = 1; upm0 = 0; break;
    case 'O': upm1 = 1; upm0 = 1; break;
    default:  upm1 = 0; upm0 = 0; break;
  }

  switch(uartport)
  {
    case 0:
      UCSR0C |= (upm1 << UPM01) | (upm0 << UPM00);
      break;
    case 1:
      UCSR1C |= (upm1 << UPM11) | (upm0 << UPM10);
      break;
    default:
      return RSP_UNKOWN_PIN;
  }

  return RSP_OK; 
}

void uart_send_usb(char uartport, char length, char *buf)
{
   answer[1] = (unsigned char)uart_send(uartport, length, buf);
   answer[2] = 0;

   CommandAnswer(3);
}


char uart_send(char uartport, unsigned int length, char *buf)
{
  if(uartport != 0 && uartport != 1)
    return RSP_UNKOWN_PIN;

  while(length--)
    uart_putchar(uartport, *buf++);

  return RSP_OK; 
}

char uart_putchar(char uartport, char data)
{
  switch(uartport)
  {
    case 0:
      /* Wait for empty transmit buffer */
      while (!(UCSR0A & (1 << UDRE0)));
      /* Put data into buffer, sends the data */
      UDR0 = data;
      break;
    case 1:
      /* Wait for empty transmit buffer */
      while (!(UCSR1A & (1 << UDRE1)));
      /* Put data into buffer, sends the data */
      UDR1 = data;
      break;
    default:
      return RSP_UNKOWN_PIN;
  }

  return RSP_OK; 
}

void uart_recv_usb(char uartport, int length)
{
   char data[length];
   int i;

   answer[1] = (char)uart_recv(uartport, data, length);

   for(i = 0; i < length; i++)
     answer[2+i] = data[i];

   answer[2+length] = 0;

   CommandAnswer(3+length);
}

char uart_recv(char uartport, char * buf, int length)
{
  if(uartport != 0 && uartport != 1)
    return RSP_UNKOWN_PIN;

  while(length-- > 0)
    *buf++ = uart_getchar(uartport);

  return RSP_OK; 
}

char uart_getchar(char uartport)
{
  char c;

  switch(uartport)
  {
    case 0:
      while (!(UCSR0A & (1 << RXC0)));
      c = UDR0;
      break;
    case 1:
      while (!(UCSR1A & (1 << RXC1)));
      c = UDR1;
      break;
    default:
      return RSP_UNKOWN_PIN;
  }

  return c;
}


